package org.xiaojinlong.explore;



abstract class Seasoning {
    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "()";
    }
}

class Salt extends Seasoning {}

//class Pepper extends Seasoning {}

class Thyme extends Seasoning {}

class Sage extends Seasoning {}

abstract class PointD {
    int x;
    int y;
    PointD(int x, int y) {
        this.x = x;
        this.y = y;
    }
    abstract int distanceToO();
    boolean closerToO(PointD point) {
        return distanceToO() <= point.distanceToO();
    }
    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + x + ", " + y + ")";
    }
}

class CartesianPt extends PointD {
    CartesianPt(int x, int y) {
        super(x, y);
    }

    @Override
    int distanceToO() {
        return (int) Math.sqrt(x * x + y * y);
    }
}

class ManhattanPt extends PointD {
    ManhattanPt(int x, int y) {
        super(x, y);
    }

    @Override
    int distanceToO() {
        return x + y;
    }
}

abstract class Num {
    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "()";
    }
}

class Zero extends Num {}

class OneMoreThan extends Num {
    Num predecessor;
    OneMoreThan(Num p) {
        predecessor = p;
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + predecessor + ")";
    }
}

abstract class Layer {
    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "()";
    }
}

class Base extends Layer {
    Object o;
    Base(Object o) {
        this.o = o;
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + o + ")";
    }
}

class Slice extends Layer {
    Layer l;
    Slice(Layer l) {
        this.l = l;
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + l + ")";
    }
}

abstract class Shish {
    abstract boolean onlyOnions();
    abstract boolean isVegetarian();
    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "()";
    }
}

class Skewer extends Shish {

    @Override
    boolean onlyOnions() {
        return true;
    }

    @Override
    boolean isVegetarian() {
        return true;
    }
}

class Onion extends Shish {
    Shish s;
    Onion(Shish s) {
        this.s = s;
    }

    @Override
    boolean onlyOnions() {
        return s.onlyOnions();
    }

    @Override
    boolean isVegetarian() {
        return s.isVegetarian();
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + s + ")";
    }
}

class Lamb extends Shish {
    Shish s;
    Lamb(Shish s) {
        this.s = s;
    }

    @Override
    boolean onlyOnions() {
        return false;
    }

    @Override
    boolean isVegetarian() {
        return false;
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + s + ")";
    }
}

class Tomato extends Shish {
    Shish s;
    Tomato(Shish s) {
        this.s = s;
    }

    @Override
    boolean onlyOnions() {
        return false;
    }

    @Override
    boolean isVegetarian() {
        return s.isVegetarian();
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + s + ")";
    }
}

abstract class KebabD {

    abstract boolean isVeggie();
    abstract Object whatHolder();

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "()";
    }
}

class Holder extends KebabD {
    Object object;
    Holder(Object o) {
        object = o;
    }

    @Override
    boolean isVeggie() {
        return true;
    }

    @Override
    Object whatHolder() {
        return object;
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + object + ")";
    }
}

class Shallot extends KebabD {
    KebabD kebab;
    Shallot(KebabD kebab) {
        this.kebab = kebab;
    }

    @Override
    boolean isVeggie() {
        return kebab.isVeggie();
    }

    @Override
    Object whatHolder() {
        return kebab.whatHolder();
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + kebab + ")";
    }

}

class Shirmp extends KebabD {
    KebabD kebab;
    Shirmp(KebabD kebab) {
        this.kebab = kebab;
    }

    @Override
    boolean isVeggie() {
        return false;
    }

    @Override
    Object whatHolder() {
        return kebab.whatHolder();
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + kebab + ")";
    }
}

class Radish extends KebabD {
    KebabD kebab;
    Radish(KebabD kebab) {
        this.kebab = kebab;
    }

    @Override
    boolean isVeggie() {
        return kebab.isVeggie();
    }

    @Override
    Object whatHolder() {
        return kebab.whatHolder();
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + kebab + ")";
    }
}

class Pepper extends KebabD {
    KebabD kebab;
    Pepper(KebabD kebab) {
        this.kebab = kebab;
    }

    @Override
    boolean isVeggie() {
        return kebab.isVeggie();
    }

    @Override
    Object whatHolder() {
        return kebab.whatHolder();
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + kebab + ")";
    }
}

class Zucchini extends KebabD {
    KebabD kebab;
    Zucchini(KebabD kebab) {
        this.kebab = kebab;
    }

    @Override
    boolean isVeggie() {
        return kebab.isVeggie();
    }

    @Override
    Object whatHolder() {
        return kebab.whatHolder();
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + kebab + ")";
    }
}

abstract class RodD {
    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "()";
    }
}

class Dagger extends RodD {
}

class Sabre extends RodD {}

class Sword extends RodD {}

abstract class PlateD {
    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "()";
    }
}

class Gold extends PlateD {}

class Silver extends PlateD {}

class Brass extends PlateD {}

class Copper extends PlateD {}

class Wood extends PlateD {}

abstract class PizzaD {
    abstract PizzaD removeAnchovy();
    abstract PizzaD topAnchovyWithCheese();
    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "()";
    }
}

class Crust extends PizzaD {
    @Override
    PizzaD removeAnchovy() {
        return new Crust();
    }

    @Override
    PizzaD topAnchovyWithCheese() {
        return new Crust();
    }
}

class Cheese extends PizzaD {
    PizzaD p;
    Cheese(PizzaD p) {
        this.p = p;
    }

    @Override
    PizzaD removeAnchovy() {
        return new Cheese(p.removeAnchovy());
    }

    @Override
    PizzaD topAnchovyWithCheese() {
        return new Cheese(p.topAnchovyWithCheese());
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + p + ")";
    }
}

class Olive extends PizzaD {
    PizzaD p;
    Olive(PizzaD p) {
        this.p = p;
    }

    @Override
    PizzaD removeAnchovy() {
        return new Olive(p.removeAnchovy());
    }

    @Override
    PizzaD topAnchovyWithCheese() {
        return new Olive(p.topAnchovyWithCheese());
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + p + ")";
    }
}

class Anchovy extends PizzaD {
    PizzaD p;
    Anchovy(PizzaD p) {
        this.p = p;
    }

    @Override
    PizzaD removeAnchovy() {
        return p.removeAnchovy();
    }

    @Override
    PizzaD topAnchovyWithCheese() {
        return new Cheese(new Anchovy(p.topAnchovyWithCheese()));
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + p + ")";
    }
}

class Sausage extends PizzaD {
    PizzaD p;
    Sausage(PizzaD p) {
        this.p = p;
    }

    @Override
    PizzaD removeAnchovy() {
        return new Sausage(p.removeAnchovy());
    }

    @Override
    PizzaD topAnchovyWithCheese() {
        return new Sausage(p.topAnchovyWithCheese());
    }

    @Override
    public String toString() {
        return "new " + getClass().getSimpleName() + "("  + p + ")";
    }
}
/**
 * Jin Long
 * 2015/8/14
 */
public class Main {
    public static void main(String[] args) {
//        System.out1.println(new Onion(new Onion(new Lamb(new Skewer()))).onlyOnions());
//        System.out1.println(
//                new Shallot(
//                        new Radish(
//                                new Holder(
//                                        new Dagger()
//                                )
//                        )
//                )
//        );
//        System.out1.println(
//                new Shallot(new Radish(new Holder(new OneMoreThan(new Zero())))).isVeggie()
//        );
//        System.out1.println(new Anchovy(new Anchovy(new Crust()).removeAnchovy()));
        System.out.println((new Olive(new Anchovy(new Cheese(new Anchovy(new Crust())))).topAnchovyWithCheese()).removeAnchovy());

    }
}